﻿Imports System.IO.IsolatedStorage
Imports System.Runtime.InteropServices
Imports System.Reflection
Imports System.Text

#If WINDOWS Then
Imports Microsoft.VisualBasic.ApplicationServices
Imports System.Drawing
Imports System.Drawing.Imaging
Imports System.Security.Principal
#End If

#If NETFX_CORE Then
Imports Windows.UI
Imports Windows.Storage.Streams
Imports System.Runtime.InteropServices.WindowsRuntime
#End If

Public Module ModuleHelper

#If WINDOWS_PHONE Then
    Public FileStorage As IsolatedStorageFile = IsolatedStorageFile.GetUserStoreForApplication()
#ElseIf SILVERLIGHT Then
    Public FileStorage As IsolatedStorageFile = IsolatedStorageFile.GetUserStoreForApplication()
    Public AppSettings As IsolatedStorageSettings = IsolatedStorageSettings.ApplicationSettings()
#Else
    Public FileStorage As IsolatedStorageFile = IsolatedStorageFile.GetUserStoreForAssembly()
    Public AppSettings As IsolatedStorageSettings = IsolatedStorageSettings.ApplicationSettings()
#End If

    Public Function IIf(Of T)(ByVal condition As Boolean, ByVal TruePart As T, ByVal FalsePart As T) As T
        If condition Then
            Return TruePart
        Else
            Return FalsePart
        End If
    End Function

#If NETFX_CORE Then

    Public Function GetIndexedColor(ByVal i As UInteger) As Color
        Dim colors = New Color() {
            Windows.UI.Colors.Red,
            Windows.UI.Colors.Orange,
            Windows.UI.Colors.Yellow,
            Windows.UI.Colors.Green,
            Windows.UI.Colors.Cyan,
            Windows.UI.Colors.Blue,
            Windows.UI.Colors.Purple
        }
        Return colors(i Mod 7)
    End Function

    Public Function GetApplicationPackageID() As String
        Return Global.Windows.ApplicationModel.Package.Current.Id.FullName
    End Function

#ElseIf WINDOWS Then

    Public Function IsAdministrator() As Boolean
        Dim identity = WindowsIdentity.GetCurrent()
        Dim principal As New WindowsPrincipal(identity)
        Return principal.IsInRole(WindowsBuiltInRole.Administrator)
    End Function

    Public Function ChangeWindowIcon(ByVal hwnd As IntPtr, ByVal path As String) As Boolean
        Try
            Dim img = Image.FromFile(path)
            Dim bmp As New Bitmap(img)
            SendMessage(hwnd, WM_SETICON, ICON_BIG, bmp.GetHicon())
            SendMessage(hwnd, WM_SETICON, ICON_SMALL, bmp.GetHicon())
            img.Dispose()
            Return True
        Catch ex As Exception
            Return False
        End Try
    End Function

    Public Function ChangeWindowIcon(ByVal hwnd As IntPtr, ByVal data() As Byte) As Boolean
        Try
            Using ms As New MemoryStream(data)
                Dim img = Image.FromStream(ms)
                Dim bmp As New Bitmap(img)
                SendMessage(hwnd, WM_SETICON, ICON_BIG, bmp.GetHicon())
                SendMessage(hwnd, WM_SETICON, ICON_SMALL, bmp.GetHicon())
                img.Dispose()
                Return True
            End Using
        Catch ex As Exception
            Return False
        End Try
    End Function

    Public Function ChangeWindowIcon(ByVal hwnd As IntPtr, ByVal bmp As Bitmap) As Boolean
        Try
            SendMessage(hwnd, WM_SETICON, ICON_BIG, bmp.GetHicon())
            SendMessage(hwnd, WM_SETICON, ICON_SMALL, bmp.GetHicon())
            Return True
        Catch ex As Exception
            Return False
        End Try
    End Function

    Public Function GetCommandLineArgs(ByVal args() As String) As List(Of String)
        Dim lst As New List(Of String)
        Try
            Dim cab As New ConsoleApplicationBase()
            If cab.IsNetworkDeployed Then
                args = AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData
                If args Is Nothing OrElse args.Length = 0 Then Exit Try
                Dim uri As New Uri(args(0))
                lst.Add(uri.LocalPath)
            Else
                If args Is Nothing Then Exit Try
                For Each item In args
                    lst.Add(item)
                Next
                Return lst
            End If
        Catch ex As Exception
            Debug.WriteLine(ex.Message & vbCrLf & ex.StackTrace.ToString())
        End Try
        Return lst
    End Function

    Public Function GetApplicationPackageID() As String
        Return My.Application.Info.LoadedAssemblies.First(Function(item) item.Location.EndsWith(".exe", StringComparison.OrdinalIgnoreCase)).GetGUID().ToString()
    End Function

    Public Function GetCallerInformation(ByVal stackFrame As StackFrame, Optional ByVal index As Integer = 0) As Tuple(Of String, String, Integer, Integer)
        Dim st As New StackTrace(stackFrame)
        Dim sf As StackFrame = st.GetFrame(index)
        Return New Tuple(Of String, String, Integer, Integer) _
            (sf.GetFileName(), sf.GetMethod().Name, sf.GetFileLineNumber(), sf.GetFileColumnNumber())
    End Function

    ''' <summary>
    ''' See if the given event has an event handler.
    ''' </summary>
    ''' <typeparam name="T"></typeparam>
    ''' <param name="Me"></param>
    ''' <param name="eventName">
    ''' The name of the event.
    ''' Case sensitive.
    ''' </param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function HasHandler(Of T)(ByVal [Me] As T, ByVal eventName As String) As Boolean
        Dim fi As FieldInfo = [Me].GetType().GetField(eventName, BindingFlags.Instance Or BindingFlags.NonPublic)
        Dim del As [Delegate] = fi.GetValue([Me])
        Return del IsNot Nothing
    End Function

    Public Function GetObjectEventList(Of T)(ByVal [Me] As T, ByVal eventName As String) As List(Of [Delegate])
        Dim lst As New List(Of [Delegate])
        Dim fi As FieldInfo = [Me].GetType().GetField(eventName, BindingFlags.Instance Or BindingFlags.NonPublic)
        Dim del = fi.GetValue([Me])
        If TypeOf del Is Array Then
            Dim arr = CType(del, Array)
            lst.AddRange(arr)
        ElseIf TypeOf del Is [Delegate] Then
            lst.Add(del)
        End If
        Return lst
    End Function

#ElseIf WINDOWS_PHONE Then

    Public Function GetApplicationPackageID() As String
        Return System.Reflection.Assembly.GetCallingAssembly().GetGUID().ToString()
    End Function

    Public Function GetCallerInformation(ByVal stackFrame As StackFrame, Optional ByVal index As Integer = 0) As Tuple(Of String, String, Integer, Integer)
        Dim st As New StackTrace(stackFrame)
        Dim sf As StackFrame = st.GetFrame(index)
        Return New Tuple(Of String, String, Integer, Integer) _
            (sf.GetFileName(), sf.GetMethod().Name, sf.GetFileLineNumber(), sf.GetFileColumnNumber())
    End Function

    Public ReadOnly Property Now() As DateTime
        Get
            Return DateTime.Now
        End Get
    End Property

#End If

    Public Function GetCurrentThreadId() As Integer
#If NETFX_CORE Then
        Dim currentTid = Environment.CurrentManagedThreadId
#Else
        Dim currentTid = System.Threading.Thread.CurrentThread.ManagedThreadId
#End If
        Return currentTid
    End Function

    ''' <summary>
    ''' Check if the given UInt32 number matches the mask.
    ''' </summary>
    ''' <param name="value"></param>
    ''' <param name="flag"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function CheckFlag(ByVal value As UInt32, ByVal flag As UInt32) As Boolean
        Return (value And flag) <> 0
    End Function

    Public Sub ParseXContainer(Of T As XContainer)(ByVal x As T, ByVal elementProcessor As Action(Of XElement), ByVal attribProcessor As Action(Of XElement, XAttribute))
        For Each element In x.Elements()
            Call elementProcessor(element)
            If element.HasAttributes Then
                For Each attr In element.Attributes()
                    Call attribProcessor(element, attr)
                Next
            End If
            If element.HasElements Then
                Call ParseXContainer(element, elementProcessor, attribProcessor)
            End If
        Next
    End Sub

End Module